//
//  CLWebViewBridge.m
//  CLBrowser
//
//  Created by 梁慧聪 on 2022/4/1.
//

#import "CLWebViewBridge.h"
#import <YYKit/NSString+YYAdd.h>
#import "CLExtentionsManager.h"
#import "CLWebDataView.h"


static dispatch_queue_t _syncQueue;

static CLWebViewBridgeQueue *_instance;
@implementation CLWebViewBridgeQueue
+ (instancetype)shareInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
        _instance.queuePool = [[YYDispatchQueuePool alloc] initWithName:@"com.cl.wk_webview_bridge_rsa_pool" queueCount:1 qos:NSQualityOfServiceUtility];
    });
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
@end

@interface NSDictionary (dictionaryToJSON)

- (NSString *)dictionaryToJSONString;

@end
@implementation NSDictionary (dictionaryToJSON)

- (NSString *)dictionaryToJSONString
{
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:nil];
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

@end

@interface CLWebViewBridge ()

@property (nonatomic, strong) NSMutableDictionary *callbacks;
@property (nonatomic, strong) NSMutableDictionary *handlers;
@property (nonatomic, strong) NSMutableDictionary *subscribes;
@end

@implementation CLWebViewBridge

//- (instancetype)initWithWebView:(CLWebView *)webView {
//    CLWebViewBridge *bridge = [CLWebViewBridge bridgeForWebView:webView];
//    if (bridge) {
//        bridge.webView = webView;
//        bridge.callbacks = [NSMutableDictionary dictionary];
//        bridge.handlers = [NSMutableDictionary dictionary];
//        bridge.subscribes = [NSMutableDictionary dictionary];
//        [CLExtentionsManager.sharedInstance addCommand:webView bridge:bridge];
//    }
//    return self;
//}

- (BOOL)shouldStartLoad:(NSURLRequest *)request pageUrl:(NSURL *)pageUrl {
    NSString *rScheme = [[request URL] scheme];
    NSString *rHost = [[request URL] host];
    NSString *pHost = [pageUrl host];
    if (pageUrl.isFileURL) {
        NSString *queryStr=[pageUrl query];
        queryStr=[NSString stringWithFormat:@"?%@",queryStr];
        pHost=[[pageUrl absoluteString] stringByReplacingOccurrencesOfString:queryStr withString:@""];
    }
    if ([rScheme isEqualToString:@"cl"]) {
        NSLog(@"[DEBUG]%@",pageUrl);
        if ([rHost isEqualToString:@"send.message"]) {
            NSString *json = [[request URL] query];
            NSDictionary *param = [self checkParams:json];
            if (param) {
                WEAK_SELF;
                dispatch_main_safe_async(^{
                    [weakSelf updateMessage:param];
                });
                return NO;
            } else {
                return YES;
            }
        } else {
            return YES;
        }
    }
    return YES;
}

- (NSDictionary *)checkParams:(NSString *)jsonValue {
    if (!jsonValue) {
        return nil;
    }
    NSError *error;
    NSString *jsonString = [jsonValue stringByURLDecode];
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *param = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
    if (!param||![param isKindOfClass:[NSDictionary class]]) {
        return nil;
    }
    return param;
}

- (void)updateMessage:(NSDictionary *)param {
    if (!param || ![param isKindOfClass:[NSDictionary class]]) return;
    NSString *cmd = param[@"cmd"];
    if (cmd) {
        void (^responseCallback)(id) = NULL;
        if (param[@"callback"]) {
            self.callbacks[cmd] = param[@"callback"];
            responseCallback = ^(id responseData) {
                if ([responseData isKindOfClass:[NSDictionary class]]) {
                    responseData = [(NSDictionary *)responseData dictionaryToJSONString];
                }
                [self p_dispatchMessage:responseData forCommand:cmd];
            };
        }
        
        void (^handler)(id, void(^)(id)) = self.handlers[cmd];
        if (handler) {
            @autoreleasepool {
                handler(param[@"jsonStr"], responseCallback);
            }
        } else {
            if (responseCallback) {
                responseCallback(@{@"msg":@"NO_CMD_FOUND",
                                   @"errcode":@(-1)});
            }
        }
    }
}

- (void)registerCommand:(NSString *)cmd handler:(void (^)(id obj, void(^responseCallback)(id obj)))handler {
    [self registerHandler:cmd handler:handler];
//    if (cmd && handler) {
//        self.handlers[cmd] = [handler copy];
//    }
}

- (void)dispatchCommand:(NSString *)cmd message:(NSString *)message {
    [self p_dispatchMessage:message forCommand:cmd];
}

- (void)callJSFunc:(NSString *)funcName withMessage:(NSString *)message {
    if (!funcName || !message) return;
    
    NSString *messageJSON = [message stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"];
//    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"];
//    messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"];
//    __strong __typeof(_webView) strongWebView = self.webView;
//    NSString* jsCmd = [NSString stringWithFormat:@"window.cl.%@('%@');",funcName, messageJSON];
//    NSLog(@"jsCmd:%@",jsCmd);
//    dispatch_main_safe_async(^{
//        [strongWebView evaluateJavaScript:jsCmd completionHandler:NULL];
//    });
}

- (void)p_dispatchMessage:(NSString *)message forCommand:(NSString *)cmd {
    NSString *callback = self.callbacks[cmd];
    if (!callback || [callback length] < 1) {
        return;
    }
    [self callJSFunc:callback withMessage:message];
}

- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback {
    dispatch_sync([self syncQueue], ^{
        [super callHandler:handlerName data:data responseCallback:responseCallback];
    });
}

- (dispatch_queue_t)syncQueue {
    if (_syncQueue == NULL) {
        _syncQueue = dispatch_queue_create("com.cl.concurrent", DISPATCH_QUEUE_CONCURRENT);
    }
    return _syncQueue;
}

@end
